// scripts/generate-api-types.ts
import { Project, SyntaxKind, ParameterDeclaration } from 'ts-morph'
import { join, dirname } from 'path'
import { ensureDir, writeFile } from 'fs-extra'

const API_DIR = join(__dirname, '../src/main/api')
const OUTPUT = join(__dirname, '../src/preload/api-types.d.ts')

async function generate(): Promise<void> {
  const project = new Project()
  project.addSourceFilesAtPaths(join(API_DIR, '*.ts'))

  const typeContent = await buildApiType(project)
  await ensureDir(dirname(OUTPUT))
  await writeFile(OUTPUT, typeContent)
  console.log(`✅ 类型声明已生成: ${OUTPUT}`)
}

async function buildApiType(project: Project): Promise<string> {
  let result = `/* Auto-generated - DO NOT EDIT */\n\n`
  result += `declare global {\n`
  result += `  interface Window {\n`
  result += `    readonly api: Api;\n`
  result += `  }\n`
  result += `}\n\n`
  result += `export interface Api {\n`

  const sourceFiles = project.getSourceFiles()

  for (const sourceFile of sourceFiles) {
    const classes = sourceFile.getClasses()

    for (const cls of classes) {
      // 获取 @IpcHandler('xxx')
      const handlerDecorator = cls.getDecorators().find((d) => d.getName() === 'IpcHandler')
      let moduleName: string | null = null

      if (handlerDecorator) {
        const args = handlerDecorator.getArguments()
        if (args.length > 0 && args[0].getKind() === SyntaxKind.StringLiteral) {
          moduleName = args[0].getText().slice(1, -1) // 去掉引号
        }
      }

      // fallback: AgentApi → agent
      if (!moduleName) {
        const className = cls.getName()
        if (className?.endsWith('Api')) {
          moduleName = className!.replace(/Api$/, '').toLowerCase()
        } else {
          continue
        }
      }

      result += `  readonly ${moduleName}: {\n`

      // 查找被 @IpcInvoke 修饰的方法
      const methods = cls.getMethods()
      for (const method of methods) {
        const invokeDec = method.getDecorators().find((d) => d.getName() === 'IpcInvoke')
        if (!invokeDec) continue

        // 获取 @IpcInvoke('xxx') 的方法名
        const arg = invokeDec.getArguments()[0]
        let methodName = 'unknown'
        if (arg && arg.getKind() === SyntaxKind.StringLiteral) {
          methodName = arg.getText().slice(1, -1)
        }

        // 获取返回类型文本
        let returnText = 'any'
        const returnTypeNode = method.getReturnTypeNode()
        if (returnTypeNode) {
          returnText = returnTypeNode.getText() // ✅ 修复：不要传参数
        } else {
          returnText = method.getReturnType().getText(method) // 用上下文推导
        }

        // 解包 Promise<T>
        while (returnText.startsWith('Promise<')) {
          const match = /^Promise<(.*)>$/.exec(returnText)
          if (!match) break
          returnText = match[1]
        }

        // 获取参数列表
        const parameters = method.getParameters()
        const params = parameters
          .map((param: ParameterDeclaration) => {
            const name = param.getName()
            const isOptional = param.hasQuestionToken() || param.isOptional() // ✅ 修复：用 hasQuestionToken()
            const typeNode = param.getTypeNode()
            const typeText = typeNode ? typeNode.getText() : param.getType().getText() // ✅ 修复：不要传参数
            return `${name}${isOptional ? '?' : ''}: ${typeText}`
          })
          .join(', ')

        result += `    readonly ${methodName}: (${params}) => Promise<${returnText}>\n`
      }

      result += `  };\n`
    }
  }

  result += `}\n\n`
  return result
}

generate().catch((err) => {
  console.error('❌ 类型生成失败:', err)
  process.exit(1)
})
